package it.koutifaris.travianmap.tile.tilemap;

import static it.koutifaris.travianmap.map.emptymap.EmptyMapSquare.emptyMapSquare;
import it.koutifaris.travianmap.map.MapSquare;
import it.koutifaris.travianmap.map.WorldMap;
import it.koutifaris.travianmap.model.Village;
import it.koutifaris.travianmap.tile.Tile;
import it.koutifaris.travianmap.tile.TileLoader;

public class TiledWorldMap implements WorldMap {

	private final TileCache tileCache;
	private final TileLoader tileLoader;
	private final int radius;

	public TiledWorldMap(TileLoader tileLoader, int radius) {
		this.tileLoader = tileLoader;
		this.radius = radius;
		this.tileCache = new TileCacheImpl();
	}

	@Override
	public MapSquare getSquareAt(int x, int y) {
		updateCache(x, y);
		return getMapSquare(x, y);
	}

	private MapSquare getMapSquare(int x, int y) {
		return (isThereAVillage(x, y)) ? newMapSquare(x, y) : emptyMapSquare();
	}

	private MapSquare newMapSquare(int x, int y) {
		MapSquareImpl result = new MapSquareImpl();
		result.setVillage(getVillageFromCache(x, y));

		return result;
	}

	private void updateCache(int x, int y) {
		if (!resulInCache(x, y)) {
			updateBoundsCache(loadTile(x, y));
		}
	}

	private void updateBoundsCache(Tile tile) {
		tileCache.add(tile);
	}

	private Tile loadTile(int x, int y) {
		return tileLoader.loadTileAt(x, y);
	}

	private boolean isThereAVillage(int x, int y) {
		return getVillageFromCache(x, y) != null;
	}

	private Village getVillageFromCache(int x, int y) {
		return tileCache.getVillageAt(x, y);
	}

	boolean resulInCache(int x, int y) {
		return tileCache.isInCache(x, y);
	}

	@Override
	public int getRadius() {
		return radius;
	}

}
